/*
 * QuickThreads -- Threads-building toolkit.
 * Copyright (c) 1993 by David Keppel
 *
 * Permission to use, copy, modify and distribute this software and
 * its documentation for any purpose and without fee is hereby
 * granted, provided that the above copyright notice and this notice
 * appear in all copies.  This software is provided as a
 * proof-of-concept and for demonstration purposes; there is no
 * representation about the suitability of this software for any
 * purpose.
 */

/* axp.s -- assembly support. */

    .text
    .align 4
    .file 2 "axp.s"

    .globl qt_block
    .globl qt_blocki
    .globl qt_abort
    .globl qt_start
    .globl qt_vstart

    /*
    ** $16: ptr to function to call once curr is suspended
    **    and control is on r19's stack.
    ** $17: 1'th arg to (*$16)(...).
    ** $18: 2'th arg to (*$16)(...).
    ** $19: sp of thread to resume.
    **
    ** The helper routine returns a value that is passed on as the
    ** return value from the blocking routine.  Since we don't
    ** touch r0 between the helper's return and the end of
    ** function, we get this behavior for free.
    */

    .ent qt_blocki
qt_blocki:
    subq $30,80, $30    /* Allocate save area. */
    stq $26, 0($30)        /* Save registers. */
    stq  $9, 8($30)
    stq $10,16($30)
    stq $11,24($30)
    stq $12,32($30)
    stq $13,40($30)
    stq $14,48($30)
    stq $15,56($30)
    stq $29,64($30)
    .end qt_blocki
    .ent qt_abort
qt_abort:
    addq $16,$31, $27    /* Put argument function in PV. */
    addq $30,$31, $16    /* Save stack ptr in outgoing arg. */
    addq $19,$31, $30    /* Set new stack pointer. */
    jsr $26,($27),0        /* Call helper function. */

    ldq $26, 0($30)        /* Restore registers. */
    ldq  $9, 8($30)
    ldq $10,16($30)
    ldq $11,24($30)
    ldq $12,32($30)
    ldq $13,40($30)
    ldq $14,48($30)
    ldq $15,56($30)
    ldq $29,64($30)

    addq $30,80, $30    /* Deallocate save area. */
    ret $31,($26),1        /* Return, predict===RET. */
    .end qt_abort


    /*
    ** Non-varargs thread startup.
    */
    .ent qt_start
qt_start:
    addq $9,$31,  $16    /* Load up `qu'. */
    addq $10,$31, $17    /* ... user function's `pt'. */
    addq $11,$31, $18    /* ... user function's `userf'. */
    addq $12,$31, $27    /* ... set procedure value to `only'. */
    jsr $26,($27),0        /* Call `only'. */

    jsr $26,qt_error    /* `only' erroniously returned. */
    .end qt_start


    .ent qt_vstart:
qt_vstart:
    /* Call startup function. */
    addq $9,$31, $16    /* Arg0 to `startup'. */
    addq $12,$31, $27    /* Set procedure value. */
    jsr $26,($27),0        /* Call `startup'. */

    /* Call user function. */
    ldt $f16, 0($30)    /* Load fp arg regs. */
    ldt $f17, 8($30)
    ldt $f18,16($30)
    ldt $f19,24($30)
    ldt $f20,32($30)
    ldt $f21,40($30)
    ldq $16,48($30)        /* And integer arg regs. */
    ldq $17,56($30)
    ldq $18,64($30)
    ldq $19,72($30)
    ldq $20,80($30)
    ldq $21,88($30)
    addq $30,96 $30        /* Pop 6*2*8 saved arg regs. */
    addq $11,$31, $27    /* Set procedure value. */
    jsr $26,($27),0        /* Call `vuserf'. */

    /* Call cleanup. */
    addq $9,$31, $16    /* Arg0 to `cleanup'. */
    addq $0,$31, $17    /* Users's return value is arg1. */
    addq $10,$31, $27    /* Set procedure value. */
    jsr $26,($27),0        /* Call `cleanup'. */

    jsr $26,qt_error    /* Cleanup erroniously returned. */
    .end qt_start


    /*
    ** Save calle-save floating-point regs $f2..$f9.
    ** Also save return pc from whomever called us.
    **
    ** Return value from `qt_block' is the same as the return from
    ** `qt_blocki'.  We get that for free since we don't touch $0
    ** between the return from `qt_blocki' and the return from
    ** `qt_block'.
    */
    .ent qt_block
qt_block:
    subq $30,80, $30    /* Allocate a save space. */
    stq $26, 0($30)        /* Save registers. */
    stt $f2, 8($30)
    stt $f3,16($30)
    stt $f4,24($30)
    stt $f5,32($30)
    stt $f6,40($30)
    stt $f7,48($30)
    stt $f8,56($30)
    stt $f9,64($30)

    jsr $26,qt_blocki    /* Call helper. */
                /* .. who will also restore $gp. */

    ldq $26, 0($30)        /* restore registers. */
    ldt $f2, 8($30)
    ldt $f3,16($30)
    ldt $f4,24($30)
    ldt $f5,32($30)
    ldt $f6,40($30)
    ldt $f7,48($30)
    ldt $f8,56($30)
    ldt $f9,64($30)

    addq $30,80, $30    /* Deallcate save space. */
    ret $31,($26),1        /* Return, predict===RET. */
    .end qt_block
